'''
Created on 25/03/2009

@author: eh01
'''
from yarra.datastore import dsconstants, dsofactory
from yarra.datastore.dst import DST
from yarra.event import eventconstants
from yarra.event.event import Event
from yarra.event.eventhandler import BaseEventHandler
from yarra.event.eventmanager import EventManager
from yarra.logging import yarralogging
from yarra.datastore.dsstub import DSStub
import cgi
import re


class IMHTTPDelegateRequestHandler(BaseEventHandler):
    '''
    Delegates to the appropriate handler to handle the HTTP request
    '''
    
    __logger = None
    __pattern_event_type = {
                           '^GET_/$':eventconstants.HTTP_REQUEST_GET_INDEX_EVENT_TYPE,
                           '^GET_/(\w|\-)+\.html':eventconstants.HTTP_REQUEST_GET_STATIC_PAGE,
                           '^POST_/connectivity-test$':eventconstants.HTTP_REQUEST_POST_CONNECTIVITY_TEST_EVENT_TYPE,
                           '^POST_/public-application-status-test$':eventconstants.HTTP_REQUEST_POST_APPLICATION_STATUS_TEST_EVENT_TYPE,
                           '^GET_/node/(\d+)(\?wait=(\w+))?$':eventconstants.HTTP_REQUEST_GET_NODE_MESSAGES_EVENT_TYPE,
                           '^GET_/node/(\d+)/(\d+)$':eventconstants.HTTP_REQUEST_GET_NODE_MESSAGE_EVENT_TYPE,
                           '^PUT_/node/(\d+)$':eventconstants.HTTP_REQUEST_PUT_NODE_MESSAGE_EVENT_TYPE,
                           '^PUT_/node/(\d+)/(\d+)$':eventconstants.HTTP_REQUEST_PUT_NODE_MESSAGE_EVENT_TYPE,
                           '^DELETE_/node/(\d+)/(\d+)$':eventconstants.HTTP_REQUEST_DELETE_NODE_MESSAGE_EVENT_TYPE,
                           '^GET_/admin$':eventconstants.HTTP_REQUEST_GET_ADMIN_EVENT_TYPE,
                           '^GET_/admin/node-last-connected$':eventconstants.HTTP_REQUEST_GET_NODE_LAST_CONNECTED_EVENT_TYPE,
                           '^GET_/admin/node$':eventconstants.HTTP_REQUEST_GET_NODE_EVENT_TYPE,
                           '^POST_/admin/flush-memcache$':eventconstants.HTTP_REQUEST_POST_FLUSH_MEMCACHE_EVENT_TYPE,
                           '^GET_/admin/logging$':eventconstants.HTTP_REQUEST_GET_LOGGING_EVENT_TYPE,
                           '^POST_/admin/logging$':eventconstants.HTTP_REQUEST_POST_LOGGING_EVENT_TYPE
                           }
    def __init__(self):
        '''
        Constructor
        '''
        self.__logger = yarralogging.get_logger(DSStub().get_application_name())
    
    def get_form_data_as_dsts(self, http_request):
        '''
        gets all the form data into a list of dsts
        '''
        dsts = []
        form = cgi.FieldStorage(
            fp=http_request.rfile, 
            headers=http_request.headers,
            environ={'REQUEST_METHOD':'POST',
                     'CONTENT_TYPE':http_request.headers['Content-Type'],
                     })
        for key in form.keys():
            dst = DST(subject=dsconstants.SUBJECT_FORM_DATA, 
                      predicate=key, 
                      literal=form[key].value)
            dsts.append(dst)
        
        if len(dsts) != 0:
            dst = DST(subject=dsconstants.SUBJECT_ROOT,
                predicate=dsconstants.PREDICATE_FORM_DATA,
                object=dsconstants.SUBJECT_FORM_DATA)
            dsts.append(dst)
        return dsts
    
    def get_http_request_body_as_dst(self, http_request):
        input_stream = http_request.rfile
        content_length = int(http_request.headers['content-length'])
        body = input_stream.read(content_length)
        dst = DST(subject=dsconstants.SUBJECT_ROOT,
            predicate=dsconstants.PREDICATE_HTTP_REQUEST_BODY,
            literal=body)
        return dst

    def get_http_header_as_dsts(self, http_request):
        content_type = http_request.headers['Content-Type']
        dst1 = DST(subject=dsconstants.SUBJECT_ROOT,
            predicate=dsconstants.PREDICATE_HTTP_REQUEST_HEADER,
            object=dsconstants.SUBJECT_HTTP_REQUEST_HEADER)
        dst2 = DST(subject=dsconstants.SUBJECT_HTTP_REQUEST_HEADER,
                   predicate=dsconstants.PREDICATE_HTTP_REQUEST_HEADER_CONTENT_TYPE,
                   literal=content_type)
        
        return [dst1, dst2]
            
    def do(self, data):
        dso = data        
        http_request = dso.get_dst(subject=dsconstants.SUBJECT_ROOT,
                    predicate=dsconstants.PREDICATE_HTTP_REQUEST).get_literal()
        method = http_request.command
        uri = http_request.path
        event_type = None
        
        # delegate the HTTP request to the correct handler
        self.__logger.info(uri)
        
        method_uri = method + "_" + uri
        
        for pattern in self.__pattern_event_type.keys():
            matches = re.match(pattern, method_uri)
            if matches:
                event_type = self.__pattern_event_type[pattern]
                if re.match('\^POST_', pattern):
                    dso.add_dsts(self.get_form_data_as_dsts(http_request))
                elif re.match('\^PUT_', pattern):
                    dso.add_dst(self.get_http_request_body_as_dst(http_request))
                    dso.add_dsts(self.get_http_header_as_dsts(http_request))
                
        if event_type is None:
            http_request = dso.get_dst(subject=dsconstants.SUBJECT_ROOT,
                        predicate=dsconstants.PREDICATE_HTTP_REQUEST).get_literal()
            lock = dso.get_dst(subject=dsconstants.SUBJECT_ROOT,
                        predicate=dsconstants.PREDICATE_LOCK).get_literal()
                        
            # create the http error dso
            dso = dsofactory.create_dso_for_http_error_handler(404, 
                                                         "URI NOT FOUND", 
                                                         http_request, 
                                                         lock)
            event_type = eventconstants.HTTP_ERROR_EVENT_TYPE 
            
        event = Event(event_type, dso)
        EventManager().add_event(event)